OpenGL 1.0 provides commands to set vertex coordinates, set the current color, color index, normal vector coordinate, and texture coordinates. The commands accept data in almost any format, but you have to execute the command many times to specify even simple geometry.
In OpenGL 1.1, you may place vertex data into arrays and then use blocks of data in these arrays to specify multiple geometric primitives through the execution of a single command. You may specify up to six arrays; one each to store edge flags, texture coordinates, colors, color indices, normals, and vertices.
The sections listed below discuss several aspects of vertex arrays that help you write more efficient OpenGL programs:
Six commands (listed below) are available to specify the arrays. A full description for normals, colors, color indexes, texture coordinates, and edge flags is not included here; see the reference pages for more information.
Table 2.4 indicates the allowable values for size and type (when present).
For type the values the following match between OpenGL and C type exist.
OpenGL Type | C Type |
---|---|
GL_BYTE | byte |
GL_SHORT | short |
GL_INT | int |
GL_FLOAT | float |
GL_UNSIGNED_BYTE | ubyte |
GL_UNSIGNED_SHORT | ushort |
GL_UNSIGNED_INT | uint |
The error GL_INVALID_VALUE is generated if size is specified with a value not included in the table.
Command | Sizes | Types |
---|---|---|
glVertexPointer | 2,3,4 | short, int, float, double |
glNormalPointer | 3 | byte, short, int, float, double |
glColorPointer | 3,4 | byte, ubyte, short, ushort, int, uint, float, double |
glIndexPointer | 1 | ubyte, short, int, float, double |
glTexCoordPointer | 1,2,3,4 | short, int, float, double |
glEdgeFlagPointer | 1 | boolean |
The one, two, three, or four values in an array that correspond to a single vertex comprise an array element. The values within each array element are stored sequentially in memory.
If stride is zero, then array elements are stored sequentially. Otherwise pointers to element i and (i + 1) of an array differ by stride basic machine units (typically unsigned bytes).
For each command, pointer specifies the location in memory of the first value of the first element of the array being specified.
To enable or disable an individual array, call one of the following functions:
void EnableClientState ( enum array ) ; void DisableClientState ( enum array ) ;
array should be set to the appropriate value shown in Table 2-5.
To transfer the ith element of an enabled array to OpenGL, call
void glArrayElement ( int i ) ;
For each enabled array, it is as though the corresponding creation command (glVertex(), glColor(), and so on) were called with a pointer to element i. For the vertex array, the corresponding command is glVertex[size][type]v, where size is one of [2,3,4], and type is one of [s,i,f,d], corresponding to array types short, int, float, and double respectively. The corresponding commands for the edge flag, texture coordinate, color, color index, and normal arrays are glEdgeFlagv, glTexCoord[size][type]v, glColor[size][type]v, glIndex[type]v, and glNormal[type]v, respectively. If the vertex array is enabled, it is as though glVertex[size][type]v is executed last, after the executions of the other corresponding commands.
Changes made to array data between the execution of glBegin() and the corresponding execution of glEnd() may affect calls to glArrayElement() that are made within the same glBegin() / glEnd() period in non-sequential ways. That is, a call to glArrayElement() that precedes a change to array data may access the changed data, and a call that follows a change to array data may access original data.
To construct a sequence of geometric primitives using elements first through count of each enabled array, call
void glDrawArrays ( enum mode, int first, sizei count ) ;
mode specifies what kind of primitives are constructed; it accepts the same token values as the mode parameter of the glBegin() command.
When you call glDrawArrays(), OpenGL, in effect, iterates through the elements in the array, starting at first and ending at count, and calls glArrayElement() for each element.
Note that the current edge flag, texture coordinates, color, color index, and normal coordinates are each indeterminate after the execution of glDrawArrays() if the corresponding array is enabled. Current values corresponding to disabled arrays are not modified by the execution of glDrawArrays().
If you've set up arrays of vertices using one of the commands listed in Table 2-5, you can then render the primitives constructed from them using glDrawElements(). To construct a sequence of vertices using the count elements whose indices are stored in *indices, call glDrawElements():
void DrawElements ( enum mode, sizei count, enum type, void *indices );
type must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT, indicating that the values in *indices are indices of GL type ubyte, ushort, or uint respectively. mode specifies what kind of primitives are constructed; it accepts the same token values as the mode parameter of the glBegin() command.
When you call glDrawElements(), OpenGL in effect iterates through the elements in the array specified in indices and calls glArrayElement() for each until it has reached count elements.
Note that the current edge flag, texture coordinates, color, color index, and normal coordinates are each indeterminate after the execution of glDrawElements(), if the corresponding array is enabled. Current values corresponding to disabled arrays are not modified by the execution of glDrawElements().
To further speed up a program that uses vertex arrays, you can call glInterleavedArrays(). The function is faster because you can specify geometry to OpenGL with a single call; you don't need to make a separate call for each type of vertex data. In addition, explicit packing (interleaving) of vertex array data is possible. (In contrast, calls to the individual functions may or may not specify packed array data.) OpenGL implementations may be able to process packed vertex data more quickly.
glInterleavedArrays() has the following prototype:
void glInterleavedArrays ( enum format, sizei stride, void *pointer )
If stride is zero, then the aggregate elements are stored consecutively; otherwise, stride bytes occur between aggregate array elements.
format serves as a "key" describing the extraction of individual arrays from the aggregate array. The following configurations are possible:
V2F | V3F | C4UB_V2F | C4UB_V3F | C3F_V3F |
N3F_V3F | C4F_N3F_V3F | T2F_V3F | T4F_V4F | T2F_C4UB_V3F |
T2F_C3F_V3F | T2F_N3F_V3F | T2F_C4F_N3F_V3F | T4F_C4F_N3F_V4F. |
Use these rules when specifying format:
If format contains a... | Then... |
T | Texture coordinates are extracted from the interleaved array. |
C | Color values are extracted. |
N | Normal values are extracted. |
Vertex coordinates are always extracted. |
The numbers 2, 3, and 4 in the format key specify how many values are extracted. F indicates that values are extracted as floating-point values. Colors may also be extracted as 4 unsigned bytes if 4UB follows the C. If a color is extracted as 4 unsigned bytes, the vertex array element which follows is located at the first possible floating-point aligned address.
Before OpenGL 1.1 was released, the OpenGL extension EXT_vertex_array provided vertex array functionality in those implementations that supported it. This section briefly lists the differences between the extension and the OpenGL 1.1 functionality:
Note: If an implementation supports both OpenGL 1.1 and the vertex array extension, applications shouldn't to mix calls to extension commands with calls to OpenGL 1.1 commands. If an application does mix calls, the results are unspecified.
glArrayElement(), glDrawArrays(), glVertexPointer(), glNormalPointer(), glColorPointer(), glIndexPointer(), glTexCoordPointer(), glEdgeFlagPointer(), glGetPointerv(), glDrawElements(), glInterleavedArrays().